/* scalar statistic */
Stathandle	\bits_rcvd_stathandle;

/* scalar statistic */
Stathandle	\bitssec_rcvd_stathandle;

/* scalar statistic */
Stathandle	\pkts_rcvd_stathandle;

/* scalar statistic */
Stathandle	\pktssec_rcvd_stathandle;

/* scalar statistic */
Stathandle	\ete_delay_stathandle;

/* scalar statistic */
Stathandle	\ete_delay_command_stathandle;

/* scalar statistic */
Stathandle	\ete_delay_data_stathandle;

/* scalar statistic */
Stathandle	\ete_delay_stathandleG;

/* scalar statistic */
Stathandle	\ete_delay_command_stathandleG;

/* scalar statistic */
Stathandle	\ete_delay_data_stathandleG;

/* totel number of bits dispatched to the network (excepted beacons) [kbits] */
double	\rcv_bits;

wpan_analyzer_statistic_vector	\statistic;

double	\max_delay;

double	\mean_delay;

/* channel utility */
double	\Umax;

/* total number of dispatched packets to the network (excepted beacons) */
int	\nbr_pkt_rcv;

/* log file handler */
FILE *	\log;

/* if enabled, the output will be saved in a log file */
Boolean	\enable_log;

/* total number of beacons bits dispatched to the network [kbits] */
double	\beacons_bits;

/* total number of beacons dispatched to the network */
int	\nbr_beacons;

/* the attributes of the node (MAC Address, PAN ID, ...) */
wpan_node_attributes	\my_attributes;

/* total number of ack bits dispatched to the network [kbits] */
double	\acks_bits;

/* total number of ACKs dispatched to the network */
int	\nbr_acks;

/* Include files					*/
#include "headers\wpan_struct.h"
#include "headers\wpan_params.h"
#include "headers\wpan_math.h"

/* Node configuration constants		*/
#define DELAY_INFINITY 1000.0
#define WPAN_DATA_RATE_KBITS (WPAN_DATA_RATE/1000.0)


/* Structures		*/	
typedef struct {
	Stathandle success_probability;
} wpan_analyzer_statistic_vector; 


/* Function prototypes */
static void wpan_analyzer_init (void);
static void wpan_analyzer_log_file_init (void);
static void wpan_analyzer_update (void);


/* Global variables*/
int app_sent_msdu_nbr; // Number of non time-critical MSDU generated by the Application Layer
double app_sent_msdu_bits; // Number of non time-critical bits generated by the Application Layer [kbits]
int app_sent_gts_msdu_nbr; // Number of GTS MSDU generated by the Application Layer
double app_sent_gts_msdu_bits; // Number of GTS bits generated by the Application Layer [kbits]
double PPDU_sent_bits = 0.0;	// Total number of bits (data and command PPDU) dispatched to the network [kbits]

/********************************************************************************* 
				IEEE 802.15.4/ZigBee OPNET Simulation Model
**********************************************************************************

Author: Petr Jurcik <petr@isep.ipp.pt> <jurcikp@control.felk.cvut.cz>
Author: Anis Koubaa <aska@isep.ipp.pt>

Organization:
	IPP-HURRAY Research Group
	CISTER/ISEP
	Polytechnic Institute of Porto, Portugal

Organization:
	Department of Control Engineering
	Faculty of Electrical Engineering
	Czech Technical University in Prague, Czech Republic
 
Copyright (c) 2007 - 2009 

This file is part of IEEE 802.15.4/ZigBee OPNET Simulation Model for OPNET Modeler. IEEE 802.15.4/ZigBee OPNET Simulation Model can be used, copied and modified under the next licenses:
 
 - GPL - GNU General Public License
 
Code can be modified and re-distributed under any combination of the above listed licenses. If a contributor does not agree with some of the licenses, he/she can delete appropriate line. If you delete all lines, you are not allowed to distribute source code and/or binaries utilizing code.


**********************************************************************************
                           GNU General Public License  

IEEE 802.15.4/ZigBee OPNET Simulation Model is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later version.
 
IEEE 802.15.4/ZigBee OPNET Simulation Model is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with IEEE 802.15.4/ZigBee OPNET Simulation Model; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 

*********************************************************************************/

/*--------------------------------------------------------------------------------
 * Function:	 wpan_analyzer_init
 *
 * Description:	initialize the process
 *				
 * No parameters
 *--------------------------------------------------------------------------------*/

static void  wpan_analyzer_init () {

	/* Stack tracing enrty point */
	FIN(wpan_analyzer_init);
	
	rcv_bits = 0;
	max_delay = 0.0;
	mean_delay = 0.0;
	nbr_pkt_rcv = 0;	
	Umax = 1.0/((900.0+MAC_HEADER_SIZE)/WPAN_DATA_RATE);
	nbr_beacons = 0;
	beacons_bits = 0;
	
	/* obtain self object ID of the surrounding processor or queue */
	my_attributes.objid = op_id_self ();	
	
	/* obtain object ID of the parent object (node) */
	my_attributes.parent_id = op_topo_parent (my_attributes.objid);
	
	/* get the name of the node */
	op_ima_obj_attr_get (my_attributes.parent_id, "name", &my_attributes.name);
	
	
	/* Stack tracing exit point */
	FOUT;
}


/*--------------------------------------------------------------------------------
 * Function:	 wpan_analyzer_log_file_init
 *
 * Description:	log file init
 *				
 * No parameters
 *--------------------------------------------------------------------------------*/

static void  wpan_analyzer_log_file_init () {

	Objid own_id;	
	Objid parent_id; 	
	char directory_path_name[120];
	char name[12];
	char log_name[132];
	
	/* Stack tracing enrty point */
	FIN(wpan_analyzer_log_file_init);	
	
	/* obtain self object ID of the surrounding processor or queue */
	own_id = op_id_self ();

	/* obtain object ID of the parent object (node) */
	parent_id = op_topo_parent (own_id);

	op_ima_obj_attr_get (parent_id, "Enable Logging", &enable_log);
	op_ima_obj_attr_get (parent_id, "Log File Directory", directory_path_name);
	op_ima_obj_attr_get (parent_id, "name", name);
	
	/* verification if the directory_path_name is a valid directory */
	if(prg_path_name_is_dir (directory_path_name) == PrgC_Path_Name_Is_Not_Dir) {
		char msg[128];
		sprintf (msg, " \"%s\" is not valid directory name. The output will not be logged.\n", directory_path_name); 
		/* Display an appropriate warning.	*/
		op_prg_odb_print_major ("Warning from wpan_analyzer_node: ", msg, OPC_NIL);	
		
		enable_log = OPC_FALSE;
	}	
	
	if (enable_log == OPC_TRUE) {
		sprintf (log_name, "%s%s.ak", directory_path_name, name); 
		printf ("Log file name: %s \n\n", log_name);
		log = fopen(log_name,"w");
	}
	
	/* Stack tracing exit point */
	FOUT;
}


/*--------------------------------------------------------------------------------
 * Function:	  wpan_analyzer_update
 *
 * Description:	initialize the process
 *				
 * No parameters
 *--------------------------------------------------------------------------------*/

static void  wpan_analyzer_update () {
	
	Packet* frame_MPDU;
	Packet* frame_PPDU;
	Packet* frame_MSDU;
	int frame_type;
	double frame_PPDU_size; // frame size in bits
	int src_addr;
	double e2e_delay;	//end-to-end delay
	int seq;	// sequence number
	int command_frm_id;
	
	/* Stack tracing enrty point */
	FIN(wpan_analyzer_update);

	switch (op_intrpt_type()) {	
		case OPC_INTRPT_STRM : // interrupt from stream - received packet (PPDU)
		{	
			frame_PPDU = op_pk_get (op_intrpt_strm ());
			frame_PPDU_size = (double) op_pk_total_size_get(frame_PPDU);
			
			/* get MAC frame (MPDU=PSDU) from received PHY frame (PPDU)*/
			op_pk_nfd_get_pkt (frame_PPDU, "PSDU", &frame_MPDU);
			
			op_pk_nfd_get(frame_MPDU, "Frame Type", &frame_type);
			op_pk_nfd_get(frame_MPDU, "Sequence Number", &seq);				
			
			switch (frame_type) {
				case BEACON_FRAME_TYPE: 
				{
					beacons_bits = beacons_bits + (frame_PPDU_size/1000.0); //kbits
					nbr_beacons = nbr_beacons + 1;
					
					if (enable_log) {			
						fprintf(log,"t = %f  -  BEACON frame number %d | SEQ = %d | TYPE = %d  | total nbr of dispatched frames = %d = %f kbits (PPDU) \n\n",op_sim_time(), nbr_beacons, seq, frame_type, nbr_beacons+nbr_pkt_rcv+nbr_acks, rcv_bits+beacons_bits+acks_bits);
						printf(" [Node %s] t=%f  -  BEACON frame number %d  | SEQ = %d | TYPE = %d  | total nbr of dispatched frames = %d = %f kbits (PPDU) \n\n", my_attributes.name, op_sim_time(), nbr_beacons, seq, frame_type, nbr_beacons+nbr_pkt_rcv+nbr_acks, rcv_bits+beacons_bits+acks_bits);
					}
					
					break;
				};
				
				case DATA_FRAME_TYPE: 
				{
					rcv_bits = rcv_bits + (frame_PPDU_size/1000.0); //kbits
					nbr_pkt_rcv = nbr_pkt_rcv + 1;
					op_pk_nfd_get (frame_MPDU, "Source Address", &src_addr);
			
					if (enable_log) {			
						fprintf(log,"t = %f  -  DATA frame from @%d | SEQ = %d | TYPE = %d  | total nbr of dispatched frames = %d = %f kbits (PPDU) \n\n",op_sim_time(), src_addr,seq, frame_type, nbr_beacons+nbr_pkt_rcv+nbr_acks, rcv_bits+beacons_bits+acks_bits);
						printf(" [Node %s] t=%f  -  DATA frame from @%d | SEQ = %d | TYPE = %d  | total nbr of dispatched frames = %d = %f kbits (PPDU) \n\n", my_attributes.name, op_sim_time(), src_addr,seq, frame_type, nbr_beacons+nbr_pkt_rcv+nbr_acks, rcv_bits+beacons_bits+acks_bits);
					}
					
					e2e_delay = op_sim_time () - op_pk_stamp_time_get (frame_MPDU);
					
					if (e2e_delay > max_delay)
						max_delay = min_double (e2e_delay, DELAY_INFINITY);
			
					mean_delay = mean_delay + e2e_delay;
					
					break;
				};
				
				case COMMAND_FRAME_TYPE: 
				{
					rcv_bits = rcv_bits + (frame_PPDU_size/1000.0); //kbits
					nbr_pkt_rcv = nbr_pkt_rcv + 1;
					op_pk_nfd_get (frame_MPDU, "Source Address", &src_addr);
					
					op_pk_nfd_get_pkt (frame_MPDU, "MSDU", &frame_MSDU);
					op_pk_nfd_get (frame_MSDU, "Command Frame Identifier", &command_frm_id);
			
					if (enable_log) {			
						fprintf(log,"t = %f  -  COMMAND frame (ID = %d) from @%d | SEQ = %d | TYPE = %d  | total nbr of dispatched frames = %d = %f kbits (PPDU) \n\n",op_sim_time(), command_frm_id, src_addr,seq, frame_type, nbr_beacons+nbr_pkt_rcv+nbr_acks, rcv_bits+beacons_bits+acks_bits);
						printf(" [Node %s] t=%f  -  COMMAND frame (ID = %d) from @%d | SEQ = %d | TYPE = %d  | total nbr of dispatched frames = %d = %f kbits (PPDU) \n\n", my_attributes.name, op_sim_time(), command_frm_id, src_addr,seq, frame_type, nbr_beacons+nbr_pkt_rcv+nbr_acks, rcv_bits+beacons_bits+acks_bits);
					}
					
					e2e_delay = op_sim_time () - op_pk_stamp_time_get (frame_MPDU);
			
					if (e2e_delay > max_delay)
						max_delay = min_double (e2e_delay, DELAY_INFINITY);
			
					mean_delay = mean_delay + e2e_delay;
					
					break;
				};
				
				case ACK_FRAME_TYPE: 
				{
					acks_bits = acks_bits + (frame_PPDU_size/1000.0); //kbits
					nbr_acks = nbr_acks + 1;
					
					if (enable_log) {			
						fprintf(log,"t = %f  -  ACK frame | SEQ = %d | TYPE = %d  | total nbr of dispatched frames = %d = %f kbits (PPDU) \n\n",op_sim_time(), seq, frame_type, nbr_beacons+nbr_pkt_rcv+nbr_acks, rcv_bits+beacons_bits+acks_bits);
						printf(" [Node %s] t=%f  -  ACK frame  | SEQ = %d | TYPE = %d  | total nbr of dispatched frames = %d = %f kbits (PPDU) \n\n", my_attributes.name, op_sim_time(), seq, frame_type, nbr_beacons+nbr_pkt_rcv+nbr_acks, rcv_bits+beacons_bits+acks_bits);
					}
					
					break;
				};
				
				
				default :
				{
				};
			}			

		
			op_stat_write (statistic.success_probability, rcv_bits/PPDU_sent_bits);	
			
			op_pk_destroy (frame_MPDU);
			op_pk_destroy (frame_PPDU);

			break;
		}
		
		case OPC_INTRPT_ENDSIM :	//end simulation interrupt
		{
		
			mean_delay = min_double (mean_delay/nbr_pkt_rcv, DELAY_INFINITY);
		
			printf ("[WPAN ANALYSER] -> SIMULATION END -  Scalar Statistics Collection\n");
			op_stat_scalar_write ("Channel Traffic G", (double)PPDU_sent_bits/(WPAN_DATA_RATE_KBITS*op_sim_time()));
			op_stat_scalar_write ("Channel Traffic G(app)", (double)app_sent_msdu_bits/(WPAN_DATA_RATE_KBITS*op_sim_time()));
			op_stat_scalar_write ("Channel Throughput S", (double)rcv_bits/(WPAN_DATA_RATE_KBITS*op_sim_time()));
			op_stat_scalar_write ("Success Probability S/G", (double)rcv_bits/PPDU_sent_bits); 
			op_stat_scalar_write ("Success Probability S/G(app)", (double)rcv_bits/app_sent_msdu_bits);
			op_stat_scalar_write ("Channel Utility Um", ((double)rcv_bits/((WPAN_DATA_RATE_KBITS*op_sim_time())*mean_delay))/Umax);
			op_stat_scalar_write ("Channel Utility Um2", ((double)rcv_bits/((WPAN_DATA_RATE_KBITS*op_sim_time())*mean_delay))*((double)rcv_bits/PPDU_sent_bits)/Umax);
			op_stat_scalar_write ("Channel Utility Um3", ((double)rcv_bits/((WPAN_DATA_RATE_KBITS*op_sim_time())))*((double)rcv_bits/PPDU_sent_bits));
			op_stat_scalar_write ("Channel Delay Dm (mean)", mean_delay);
			op_stat_scalar_write ("Channel Delay DM (max)", max_delay);
		
					
			if (enable_log == OPC_TRUE) {
				printf("TOTAL NUMBER OF DISPATCHED FRAMES TO THE NETWORK		= %d = %.3f kbits (PPDU)\n", nbr_beacons+nbr_pkt_rcv+nbr_acks, rcv_bits+beacons_bits+acks_bits);
				printf("TOTAL NUMBER OF DISPATCHED BEACONS TO THE NETWORK		= %d = %.3f kbits (PPDU)\n", nbr_beacons, beacons_bits);				
				printf("TOTAL SIZE OF GENERATED MSDUs FOR CAP (APP LAYER)		= %.3f kbits\n", app_sent_msdu_bits);
				printf("TOTAL NUMBER OF GENERATED MSDUs FOR CAP (APP LAYER)		= %d \n", app_sent_msdu_nbr);
				printf("TOTAL SIZE OF GENERATED MSDUs FOR GTS (APP LAYER)		= %.3f kbits\n", app_sent_gts_msdu_bits);
				printf("TOTAL NUMBER OF GENERATED MSDUs FOR GTS (APP LAYER)		= %d \n", app_sent_gts_msdu_nbr);
				printf("Channel Traffic G    = %f \n", (double)PPDU_sent_bits/(WPAN_DATA_RATE_KBITS*op_sim_time()));
				printf("Channel Traffic Gapp = %f \n", (double)app_sent_msdu_bits/(WPAN_DATA_RATE_KBITS*op_sim_time()));
				printf("Channel Traffic S    = %f \n", (double)rcv_bits/(WPAN_DATA_RATE_KBITS*op_sim_time()));
				printf("Channel Utility Um   = %f \n", (double)rcv_bits/((WPAN_DATA_RATE_KBITS*op_sim_time())*mean_delay));
				printf("Channel Utility UM   = %f \n", (double)rcv_bits/((WPAN_DATA_RATE_KBITS*op_sim_time())*max_delay));
				printf("Channel Delay Dm (mean)	= %f sec \n", mean_delay);
				printf("Channel Delay DM (max)	= %f sec \n", max_delay);		
				printf("SUCCESS PROBABILITY  	= %f \n", rcv_bits/PPDU_sent_bits);
			
				fprintf(log,"TOTAL NUMBER OF DISPATCHED FRAMES TO THE NETWORK		= %d = %.3f kbits (PPDU)\n", nbr_beacons+nbr_pkt_rcv+nbr_acks, rcv_bits+beacons_bits+acks_bits);
				fprintf(log,"TOTAL NUMBER OF DISPATCHED BEACONS TO THE NETWORK		= %d = %.3f kbits (PPDU)\n", nbr_beacons, beacons_bits);
				fprintf(log,"TOTAL SIZE OF GENERATED MSDUs FOR CAP (APP LAYER)		= %.3f kbits \n", app_sent_msdu_bits);
				fprintf(log,"TOTAL NUMBER OF GENERATED MSDUs FOR CAP (APP LAYER)	= %d \n", app_sent_msdu_nbr);
				fprintf(log,"TOTAL SIZE OF GENERATED MSDUs FOR GTS (APP LAYER)		= %.3f kbits \n", app_sent_gts_msdu_bits);
				fprintf(log,"TOTAL NUMBER OF GENERATED MSDUs FOR GTS (APP LAYER)	= %d \n", app_sent_gts_msdu_nbr);
				fprintf(log,"Channel Traffic G    = %f \n", (double)PPDU_sent_bits/(WPAN_DATA_RATE_KBITS*op_sim_time()));
				fprintf(log,"Channel Traffic Gapp = %f \n", (double)app_sent_msdu_bits/(WPAN_DATA_RATE_KBITS*op_sim_time()));
				fprintf(log,"Channel Traffic S    = %f \n", (double)rcv_bits/(WPAN_DATA_RATE_KBITS*op_sim_time()));		
				fprintf(log,"Channel Utility Um   = %f \n", (double)rcv_bits/((WPAN_DATA_RATE_KBITS*op_sim_time())*mean_delay));
				fprintf(log,"Channel Utility UM   = %f \n", (double)rcv_bits/((WPAN_DATA_RATE_KBITS*op_sim_time())*max_delay));		
				fprintf(log,"Channel Delay Dm (mean)	= %f sec \n", mean_delay);
				fprintf(log,"Channel Delay DM (max)		= %f sec \n", max_delay);			
				fprintf(log,"SUCCESS PROBABILITY		= %f \n", rcv_bits/PPDU_sent_bits);
		
				fclose(log);
			}
		
			break;
		}

		default :
		{
		}
	}
	
	/* Stack tracing exit point */
	FOUT;
}

/*
wpan_analyzer_init ();
wpan_analyzer_log_file_init ();
	
/* Register the statistics that will be maintained by this model.	
statistic.success_probability = op_stat_reg ("Success Probability", OPC_STAT_INDEX_NONE, OPC_STAT_LOCAL);

//idle state
wpan_analyzer_update ();

*/